package com.durian.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.durian.config.ServiceException;
import com.durian.domain.DTO.ObsDefaultListDTO;
import com.durian.domain.DTO.ObsShopcarAddDTO;
import com.durian.domain.DTO.ObsShopcarUpdateDTO;
import com.durian.domain.VO.ObsShopcarListVO;
import com.durian.domain.entity.ObsAddress;
import com.durian.domain.entity.ObsShopcar;
import com.durian.domain.entity.ObsUser;
import com.durian.mapper.ObsAddressMapper;
import com.durian.mapper.ObsShopcarMapper;
import com.durian.mapper.ObsUserMapper;
import com.durian.service.IObsShopcarService;
import com.durian.utils.PageInfoResult;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;

/**
 * <p>
 * 购物车表 服务实现类
 * </p>
 *
 * @author Durian
 * @since 2023-11-23
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ObsShopcarServiceImpl extends ServiceImpl<ObsShopcarMapper, ObsShopcar> implements IObsShopcarService {

    @Value("${default.pageNum}")
    private Integer pageNum;

    @Value("${default.pageSize}")
    private Integer pageSize;

    private final ObsShopcarMapper shopcarMapper;

    private final ObsUserMapper userMapper;

    private final ObsAddressMapper addressMapper;

    @Override
    @Transactional
    public void addShopCar(ObsShopcarAddDTO shopcarAddDTO) {

        Long userId = shopcarAddDTO.getUserId();
        Long addressId = shopcarAddDTO.getAddressId();
        Long bookId = shopcarAddDTO.getBookId();
        Integer bookCount = shopcarAddDTO.getBookCount();

        // 检查用户是否存在
        LambdaQueryWrapper<ObsUser> userExistWrapper = new LambdaQueryWrapper<ObsUser>()
                .select(ObsUser::getUserId)
                .eq(ObsUser::getUserId, userId);
        if (!userMapper.exists(userExistWrapper)) {
            throw new ServiceException("用户不存在");
        }
        // 检查用户的地址是否存在
        LambdaQueryWrapper<ObsAddress> addressExistWrapper = new LambdaQueryWrapper<ObsAddress>()
                .select(ObsAddress::getAddressId)
                .eq(ObsAddress::getAddressId, addressId)
                .eq(ObsAddress::getUserId, userId);
        if (!addressMapper.exists(addressExistWrapper)) {
            throw new ServiceException("用户该地址不存在");
        }

        // 检查书籍是否在购物车中
        LambdaQueryWrapper<ObsShopcar> shopcarExistWrapper = new LambdaQueryWrapper<ObsShopcar>()
                .eq(ObsShopcar::getUserId, userId)
                .eq(ObsShopcar::getAddressId,addressId)
                .eq(ObsShopcar::getBookId, bookId);
        ObsShopcar shopcar = shopcarMapper.selectOne(shopcarExistWrapper);

        // 书籍在购物车内，则书籍数量累加
        if (ObjectUtils.isNotNull(shopcar)) {
            // 获取购物车内书籍的数量
            Integer oldBookCount = shopcar.getBookCount();
            // 对书籍数量进行累加
            Integer newBookCount = bookCount + oldBookCount;

            LambdaUpdateWrapper<ObsShopcar> updateShopcarWrapper = new LambdaUpdateWrapper<ObsShopcar>()
                    .set(ObsShopcar::getBookCount, newBookCount)
                    .eq(ObsShopcar::getShopcarId, shopcar.getShopcarId());
            int updateShopcar = shopcarMapper.update(new ObsShopcar(), updateShopcarWrapper);
            if (updateShopcar != 1) {
                log.error("数据库错误：{} = shopcarMapper.update({})", updateShopcar, updateShopcarWrapper.getSqlSet());
                throw new ServiceException("系统错误");
            }
        }
        // 购物车中没有该书籍, 新增书籍
        else {
            // 将信息从DTO中获取出来
            ObsShopcar shopcarNew = new ObsShopcar();
            BeanUtils.copyProperties(shopcarAddDTO, shopcarNew);

            // 添加进购物车
            int insertShopcar = shopcarMapper.insert(shopcarNew);
            if (insertShopcar != 1) {
                log.error("数据库错误：{} = shopcarMapper.insert({})", insertShopcar, shopcarNew);
                throw new ServiceException("系统错误");
            }
        }
    }

    @Override
    @Transactional
    public void removeShopcar(List<Long> ids) {

        // 检查要移除的记录是否存在
        ids.forEach(id -> {
            LambdaQueryWrapper<ObsShopcar> shopcarExistWrapper = new LambdaQueryWrapper<ObsShopcar>()
                    .select(ObsShopcar::getShopcarId)
                    .eq(ObsShopcar::getShopcarId, id);

            if (!shopcarMapper.exists(shopcarExistWrapper)) {
                log.error("找不到要移除的记录！");
                throw new ServiceException("找不到要移除的记录！");
            }
        });

        // 移除购物车表的记录
        LambdaUpdateWrapper<ObsShopcar> shopcarRemoveWrapper = new LambdaUpdateWrapper<ObsShopcar>()
                .in(ObsShopcar::getShopcarId, ids);
        int removeShopcar = shopcarMapper.delete(shopcarRemoveWrapper);

        if (removeShopcar <= 0) {
            log.error("数据库未知：{} = shopcarMapper.delete()", removeShopcar);
            throw new ServiceException("系统错误");
        }
    }

    @Override
    @Transactional
    public void updateShopcar(ObsShopcarUpdateDTO shopcarUpdateDTO) {

        Long shopcarId = shopcarUpdateDTO.getShopcarId();
        Long userId = shopcarUpdateDTO.getUserId();
        Long bookId = shopcarUpdateDTO.getBookId();
        Long addressId = shopcarUpdateDTO.getAddressId();
        Date bookAddDate = shopcarUpdateDTO.getBookAddDate();
        Integer bookCount = shopcarUpdateDTO.getBookCount();

        // 检查购物车信息是否存在
        LambdaQueryWrapper<ObsShopcar> shopcarExistWrapper = new LambdaQueryWrapper<ObsShopcar>()
                .select(ObsShopcar::getShopcarId)
                .eq(ObsShopcar::getShopcarId, shopcarId);
        if (!shopcarMapper.exists(shopcarExistWrapper)) {
            throw new ServiceException("信息不存在，更新失败！");
        }

        // 设置更新信息
        LambdaUpdateWrapper<ObsShopcar> shopcarUpdateWrapper = new LambdaUpdateWrapper<ObsShopcar>()
                .set(ObjectUtils.isNotNull(userId), ObsShopcar::getUserId, userId)
                .set(ObjectUtils.isNotNull(bookId), ObsShopcar::getBookId, bookId)
                .set(ObjectUtils.isNotNull(addressId), ObsShopcar::getAddressId, addressId)
                .set(ObjectUtils.isNotNull(bookAddDate), ObsShopcar::getBookAddDate, bookAddDate)
                .set(ObjectUtils.isNotNull(bookCount), ObsShopcar::getBookCount, bookCount)
                .eq(ObsShopcar::getShopcarId, shopcarId);

        // 更新购物车信息
        int updateShopcar = shopcarMapper.update(new ObsShopcar(), shopcarUpdateWrapper);
        if (updateShopcar != 1) {
            log.error("数据库未知：{} = shopcarMapper.delete()", updateShopcar);
            throw new ServiceException("系统错误");
        }

    }

    @Override
    @Transactional(propagation = Propagation.SUPPORTS)
    public PageInfoResult<ObsShopcarListVO> listShopcar(ObsDefaultListDTO defaultListDTO) {

        Integer pageNum = defaultListDTO.getPageNum();
        Integer pageSize = defaultListDTO.getPageSize();

        // 检查分页页码和大小
        if (ObjectUtils.isNull(pageNum)) {
            pageNum = this.pageNum;
        }
        if (ObjectUtils.isNull(pageSize)) {
            pageSize = this.pageSize;
        }

        // 分页查询
        PageInfo<ObsShopcar> pageInfo = PageHelper
                .startPage(pageNum, pageSize)
                .doSelectPageInfo(() -> shopcarMapper.listShopcar(defaultListDTO));

        return PageInfoResult.of(pageInfo, ObsShopcarListVO.class);
    }

    public List<ObsShopcarListVO> getShopcar(Long userId){

        // 检查用户是否存在
        LambdaQueryWrapper<ObsUser> userExistWrapper = new LambdaQueryWrapper<ObsUser>()
                .select(ObsUser::getUserId)
                .eq(ObsUser::getUserId, userId);
        if (!userMapper.exists(userExistWrapper)) {
            throw new ServiceException("用户不存在");
        }

        return shopcarMapper.listShopcarById(userId);
    }
}
